#pragma once
#include <iostream>
#include <algorithm>
#include <sys/select.h>
#include <sys/time.h>
#include "Socket.hpp"
#include "Log.hpp"
using std::cout;
using std::endl;
const static int default_port = 8888;
const static int max_size = 1024;
const static int default_val = -1;
class SelectServer
{
public:
    SelectServer(int port = default_port)
        : _port(port)
    {
    }
    ~SelectServer()
    {
        _listenSock.Close();
    }
    void Init()
    {
        _listenSock.Socket();
        _listenSock.Bind(_port);
        _listenSock.Listen();
        for (size_t i = 0; i < max_size; i++)
        {
            _rfds[i] = default_val;
        }
        // for (size_t i = 0; i < max_size; i++)
        // {
        //     cout <<  _rfds[i] << endl;
        // }
    }

    void PrintFd()
    {
        cout << "rfds: ";
        for (size_t i = 0; i < max_size; i++)
        {
            if(_rfds[i] != default_val)
            {
                cout << _rfds[i] << " ";
            }
            cout << endl;
        }
        
    }
    void Start()
    {
        int listenSock = _listenSock.Fd();
        _rfds[0] = listenSock;
        while (1)
        {
            fd_set fds;
            FD_ZERO(&fds);
            int maxFd = _rfds[0];
            for (size_t i = 0; i < max_size; i++)
            {
                if (_rfds[i] != default_val)
                {
                    FD_SET(_rfds[i], &fds);
                    maxFd = std::max(maxFd, _rfds[i]);
                }
            }
            cout << "maxFd: " << maxFd << endl;
            struct timeval timeout = {3, 0};
            int n = select(maxFd + 1, &fds, nullptr, nullptr, /*&timeout*/ nullptr);
            switch (n)
            {
            case 0:
                cout << "time out" << endl;
                break;
            case -1:
                break;
            default:
                Dispatcher(fds);
                break;
            }
        }
    }   
    void Dispatcher(fd_set& fds)
    {
        for (size_t i = 0; i < max_size; i++)
        {
            if(_rfds[i] != default_val && FD_ISSET(_rfds[i], &fds))
            {
                if(_rfds[i] == _listenSock.Fd())
                {
                    Accepter();
                    //PrintFd();
                }
                else
                {
                    Recver(_rfds[i], i);
                }
            }
        }
    }

    void Accepter()
    {
        std::string clientIp;
        uint16_t clientPort;
        int sock = _listenSock.Accept(&clientIp, &clientPort);
        lg(Info, "Accept a new sock: %d, clientip: %s, clientport: %d", sock, clientIp.c_str(), clientPort);
        size_t i = 0;
        for (; i < max_size; i++)
        {
            if(_rfds[i] == default_val)
            {
                _rfds[i] = sock;
                break;
            }
        }
        if(i == max_size)
        {
            lg(Warning, "server is full");
            close(sock);
        }
        
    }
    void Recver(int sock, int pos)
    {
        char buffer[1024];
        ssize_t n = read(sock, buffer, sizeof(buffer) - 1);
        if(n > 0)
        {
            buffer[n] = 0;
            cout << "echo# " << buffer << endl;
        }
        else if(n == 0)
        {
            printf("client quit, i will close sock: %d", sock);
            _rfds[pos] = default_val;
            close(sock);
            return;
        }
        else
        {
            cout << "client quit,i will close sock" << endl;
            _rfds[pos] = default_val;
            close(sock);
            return;
        }

    }
private:
    Sock _listenSock;
    uint16_t _port;
    int _rfds[max_size];
};